Odkryj moc Federacji GraphQL dzięki Schema Stitching. Dowiedz się, jak budować zunifikowane API GraphQL z wielu usług, poprawiając skalowalność i łatwość utrzymania.
Federacja GraphQL: Schema Stitching - Kompleksowy przewodnik
W stale ewoluującym krajobrazie nowoczesnego tworzenia aplikacji potrzeba skalowalnych i łatwych w utrzymaniu architektur stała się najważniejsza. Mikrousługi, z ich wrodzoną modularnością i niezależnością wdrożeń, stały się popularnym rozwiązaniem. Jednak zarządzanie licznymi mikrousługami może wprowadzać komplikacje, zwłaszcza jeśli chodzi o udostępnianie zunifikowanego API aplikacjom klienckim. W tym miejscu do gry wchodzi Federacja GraphQL, a w szczególności Schema Stitching.
Czym jest Federacja GraphQL?
Federacja GraphQL to potężna architektura, która pozwala na budowę jednego, zunifikowanego API GraphQL z wielu bazowych usług GraphQL (często reprezentujących mikrousługi). Umożliwia ona deweloperom odpytywanie danych z różnych usług, jakby były jednym grafem, upraszczając doświadczenie klienta i redukując potrzebę skomplikowanej logiki orkiestracji po stronie klienta.
Istnieją dwa główne podejścia do Federacji GraphQL:
- Schema Stitching: Polega na łączeniu wielu schematów GraphQL w jeden, zunifikowany schemat na warstwie bramki (gateway). Jest to wcześniejsze podejście, które opiera się na bibliotekach do zarządzania łączeniem schematów i delegowaniem zapytań.
- Apollo Federation: Jest to nowsze i bardziej solidne podejście, które wykorzystuje deklaratywny język schematów i dedykowany planer zapytań do zarządzania procesem federacji. Oferuje zaawansowane funkcje, takie jak rozszerzenia typów, dyrektywy kluczy i rozproszone śledzenie.
Ten artykuł koncentruje się na Schema Stitching, zgłębiając jego koncepcje, korzyści, ograniczenia i praktyczną implementację.
Zrozumienie Schema Stitching
Schema Stitching to proces łączenia wielu schematów GraphQL w jeden, spójny schemat. Ten zunifikowany schemat działa jak fasada, ukrywając złożoność bazowych usług przed klientem. Gdy klient wysyła żądanie do połączonego schematu, bramka inteligentnie przekierowuje żądanie do odpowiedniej usługi lub usług, pobiera dane i łączy wyniki przed zwróceniem ich do klienta.
Wyobraź to sobie w ten sposób: Masz wiele restauracji (usług), z których każda specjalizuje się w innej kuchni. Schema Stitching jest jak uniwersalne menu, które łączy wszystkie dania z każdej restauracji. Kiedy klient (klient) zamawia z uniwersalnego menu, zamówienie jest inteligentnie kierowane do odpowiednich kuchni restauracyjnych, jedzenie jest przygotowywane, a następnie łączone w jedną dostawę dla klienta.
Kluczowe pojęcia w Schema Stitching
- Zdalne schematy (Remote Schemas): Są to indywidualne schematy GraphQL każdej z bazowych usług. Każda usługa udostępnia swój własny schemat, który definiuje dane i operacje, jakie dostarcza.
- Bramka (Gateway): Bramka jest centralnym komponentem odpowiedzialnym za łączenie zdalnych schematów i udostępnianie zunifikowanego schematu klientowi. Odbiera żądania klienta, przekierowuje je do odpowiednich usług i łączy wyniki.
- Łączenie schematów (Schema Merging): Jest to proces łączenia zdalnych schematów w jeden schemat. Często wiąże się to ze zmianą nazw typów i pól w celu uniknięcia konfliktów oraz definiowaniem relacji między typami z różnych schematów.
- Delegowanie zapytań (Query Delegation): Gdy klient wysyła żądanie do połączonego schematu, bramka musi delegować żądanie do odpowiedniej usługi lub usług w celu pobrania danych. Polega to na przetłumaczeniu zapytania klienta na zapytanie, które może być zrozumiane przez zdalną usługę.
- Agregacja wyników (Result Aggregation): Po pobraniu danych z bazowych usług, bramka musi połączyć wyniki w jedną odpowiedź, która może być zwrócona do klienta. Często wiąże się to z transformacją danych, aby dopasować je do struktury połączonego schematu.
Korzyści z Schema Stitching
Schema Stitching oferuje kilka istotnych korzyści dla organizacji wdrażających architekturę mikrousług:
- Zunifikowane API: Zapewnia jedno, spójne API dla klientów, upraszczając dostęp do danych i zmniejszając potrzebę bezpośredniej interakcji klientów z wieloma usługami. Skutkuje to czystszym i bardziej intuicyjnym doświadczeniem deweloperskim.
- Zmniejszona złożoność po stronie klienta: Klienci muszą komunikować się tylko ze zunifikowanym schematem, co chroni ich przed złożonością bazowej architektury mikrousług. Upraszcza to rozwój po stronie klienta i zmniejsza ilość wymaganego kodu.
- Zwiększona skalowalność: Pozwala na niezależne skalowanie poszczególnych usług w zależności od ich specyficznych potrzeb. Poprawia to ogólną skalowalność i odporność systemu. Na przykład, usługa użytkowników doświadczająca dużego obciążenia może być skalowana bez wpływu na inne usługi, takie jak katalog produktów.
- Poprawiona łatwość utrzymania: Promuje modularność i separację odpowiedzialności, co ułatwia utrzymanie i rozwijanie poszczególnych usług. Zmiany w jednej usłudze mają mniejszą szansę na wpłynięcie na inne usługi.
- Stopniowe wdrażanie: Może być implementowane stopniowo, co pozwala na powolną migrację z architektury monolitycznej do architektury mikrousług. Można zacząć od połączenia istniejących API, a następnie stopniowo dekomponować monolit na mniejsze usługi.
Ograniczenia Schema Stitching
Mimo że Schema Stitching oferuje liczne zalety, ważne jest, aby być świadomym jego ograniczeń:
- Złożoność: Implementacja i zarządzanie schema stitching może być skomplikowane, zwłaszcza w dużych i złożonych systemach. Niezbędne jest staranne planowanie i projektowanie.
- Narzut wydajnościowy: Bramka wprowadza pewien narzut wydajnościowy z powodu dodatkowej warstwy pośredniej oraz potrzeby delegowania zapytań i agregowania wyników. Staranne optymalizacje są kluczowe, aby zminimalizować ten narzut.
- Konflikty schematów: Konflikty mogą pojawić się podczas łączenia schematów z różnych usług, zwłaszcza jeśli używają tych samych nazw typów lub pól. Wymaga to starannego projektowania schematów i potencjalnej zmiany nazw typów i pól.
- Ograniczone funkcje zaawansowane: W porównaniu do Apollo Federation, Schema Stitching brakuje niektórych zaawansowanych funkcji, takich jak rozszerzenia typów i dyrektywy kluczy, co może utrudniać zarządzanie relacjami między typami z różnych schematów.
- Dojrzałość narzędzi: Narzędzia i ekosystem wokół Schema Stitching nie są tak dojrzałe jak te wokół Apollo Federation. Może to utrudniać debugowanie i rozwiązywanie problemów.
Praktyczna implementacja Schema Stitching
Przeanalizujmy uproszczony przykład implementacji Schema Stitching przy użyciu Node.js i biblioteki graphql-tools
(popularny wybór do łączenia schematów). Ten przykład obejmuje dwie mikrousługi: usługę użytkownika i usługę produktu.
1. Zdefiniuj zdalne schematy
Najpierw zdefiniuj schematy GraphQL dla każdej ze zdalnych usług.
Usługa użytkownika (user-service.js
):
const { buildSchema } = require('graphql');
const userSchema = buildSchema(`
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
`);
const users = [
{ id: '1', name: 'Alice Smith', email: 'alice@example.com' },
{ id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];
const userRoot = {
user: (args) => users.find(user => user.id === args.id),
};
module.exports = {
schema: userSchema,
rootValue: userRoot,
};
Usługa produktu (product-service.js
):
const { buildSchema } = require('graphql');
const productSchema = buildSchema(`
type Product {
id: ID!
name: String
price: Float
userId: ID! # Klucz obcy do usługi użytkownika
}
type Query {
product(id: ID!): Product
}
`);
const products = [
{ id: '101', name: 'Laptop', price: 1200, userId: '1' },
{ id: '102', name: 'Smartphone', price: 800, userId: '2' },
];
const productRoot = {
product: (args) => products.find(product => product.id === args.id),
};
module.exports = {
schema: productSchema,
rootValue: productRoot,
};
2. Utwórz usługę bramki (Gateway)
Teraz utwórz usługę bramki, która połączy oba schematy.
Usługa bramki (gateway.js
):
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');
async function createRemoteSchema(uri) {
const fetcher = async (params) => {
const response = await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
return response.json();
};
const schema = await introspectSchema(fetcher);
return makeRemoteExecutableSchema({
schema,
fetcher,
});
}
async function main() {
const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
const productSchema = await createRemoteSchema('http://localhost:4002/graphql');
const stitchedSchema = stitchSchemas({
subschemas: [
{ schema: userSchema },
{ schema: productSchema },
],
typeDefs: `
extend type Product {
user: User
}
`,
resolvers: {
Product: {
user: {
selectionSet: `{ userId }`,
resolve(product, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: userSchema,
operation: 'query',
fieldName: 'user',
args: {
id: product.userId,
},
context,
info,
});
},
},
},
},
});
const app = express();
app.use('/graphql', graphqlHTTP({
schema: stitchedSchema,
graphiql: true,
}));
app.listen(4000, () => console.log('Gateway server running on http://localhost:4000/graphql'));
}
main().catch(console.error);
3. Uruchom usługi
Musisz uruchomić usługę użytkownika i usługę produktu na różnych portach. Na przykład:
Usługa użytkownika (port 4001):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4001, () => console.log('User service running on http://localhost:4001/graphql'));
Usługa produktu (port 4002):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4002, () => console.log('Product service running on http://localhost:4002/graphql'));
4. Wykonaj zapytanie do połączonego schematu
Teraz możesz wykonywać zapytania do połączonego schematu za pośrednictwem bramki (działającej na porcie 4000). Możesz uruchomić zapytanie takie jak to:
query {
product(id: "101") {
id
name
price
user {
id
name
email
}
}
}
To zapytanie pobiera produkt o ID "101", a także pobiera powiązanego użytkownika z usługi użytkownika, co pokazuje, jak Schema Stitching pozwala na odpytywanie danych z wielu usług w jednym żądaniu.
Zaawansowane techniki Schema Stitching
Oprócz podstawowego przykładu, oto kilka zaawansowanych technik, które można wykorzystać do ulepszenia implementacji Schema Stitching:
- Delegacja schematu: Pozwala na delegowanie części zapytania do różnych usług w zależności od żądanych danych. Na przykład, można delegować rozwiązywanie typu `User` do usługi użytkownika, a rozwiązywanie typu `Product` do usługi produktu.
- Transformacja schematu: Polega na modyfikowaniu schematu zdalnej usługi przed jego połączeniem w zunifikowany schemat. Może to być przydatne do zmiany nazw typów i pól, dodawania nowych pól lub usuwania istniejących.
- Niestandardowe resolwery: Można definiować niestandardowe resolwery w bramce do obsługi złożonych transformacji danych lub do pobierania danych z wielu usług i łączenia ich w jeden wynik.
- Udostępnianie kontekstu: Często konieczne jest udostępnianie informacji kontekstowych między bramką a zdalnymi usługami, takich jak tokeny uwierzytelniające lub identyfikatory użytkowników. Można to osiągnąć, przekazując informacje kontekstowe w ramach procesu delegowania zapytania.
- Obsługa błędów: Zaimplementuj solidną obsługę błędów, aby elegancko zarządzać błędami występującymi w zdalnych usługach. Może to obejmować logowanie błędów, zwracanie przyjaznych dla użytkownika komunikatów o błędach lub ponawianie nieudanych żądań.
Wybór między Schema Stitching a Apollo Federation
Chociaż Schema Stitching jest realną opcją dla Federacji GraphQL, Apollo Federation stała się popularniejszym wyborem ze względu na zaawansowane funkcje i lepsze doświadczenie programistyczne. Oto porównanie obu podejść:
Cecha | Schema Stitching | Apollo Federation |
---|---|---|
Definicja schematu | Używa istniejącego języka schematów GraphQL | Używa deklaratywnego języka schematów z dyrektywami |
Planowanie zapytań | Wymaga ręcznego delegowania zapytań | Automatyczne planowanie zapytań przez Apollo Gateway |
Rozszerzenia typów | Ograniczone wsparcie | Wbudowane wsparcie dla rozszerzeń typów |
Dyrektywy kluczy | Brak wsparcia | Używa dyrektywy @key do identyfikacji encji |
Rozproszone śledzenie | Wymaga ręcznej implementacji | Wbudowane wsparcie dla rozproszonego śledzenia |
Narzędzia i ekosystem | Mniej dojrzałe narzędzia | Bardziej dojrzałe narzędzia i duża społeczność |
Złożoność | Może być skomplikowane w zarządzaniu w dużych systemach | Zaprojektowane dla dużych i złożonych systemów |
Kiedy wybrać Schema Stitching:
- Masz istniejące usługi GraphQL i chcesz je szybko połączyć.
- Potrzebujesz prostego rozwiązania federacyjnego i nie wymagasz zaawansowanych funkcji.
- Masz ograniczone zasoby i chcesz uniknąć narzutu związanego z konfiguracją Apollo Federation.
Kiedy wybrać Apollo Federation:
- Budujesz duży i złożony system z wieloma zespołami i usługami.
- Potrzebujesz zaawansowanych funkcji, takich jak rozszerzenia typów, dyrektywy kluczy i rozproszone śledzenie.
- Chcesz bardziej solidnego i skalowalnego rozwiązania federacyjnego.
- Preferujesz bardziej deklaratywne i zautomatyzowane podejście do federacji.
Przykłady z życia wzięte i przypadki użycia
Oto kilka rzeczywistych przykładów wykorzystania Federacji GraphQL, w tym Schema Stitching:
- Platforma e-commerce: Platforma e-commerce może używać Federacji GraphQL do łączenia danych z wielu usług, takich jak usługa katalogu produktów, usługa użytkowników, usługa zamówień i usługa płatności. Pozwala to klientom na łatwe pobieranie wszystkich informacji potrzebnych do wyświetlania szczegółów produktów, profili użytkowników, historii zamówień i informacji o płatnościach.
- Platforma mediów społecznościowych: Platforma mediów społecznościowych mogłaby używać Federacji GraphQL do łączenia danych z usług zarządzających profilami użytkowników, postami, komentarzami i polubieniami. Umożliwia to klientom efektywne pobieranie wszystkich informacji wymaganych do wyświetlania profilu użytkownika, jego postów oraz komentarzy i polubień z nimi związanych.
- Aplikacja usług finansowych: Aplikacja finansowa może używać Federacji GraphQL do łączenia danych z usług zarządzających kontami, transakcjami i inwestycjami. Pozwala to klientom na łatwe pobieranie wszystkich informacji potrzebnych do wyświetlania sald kont, historii transakcji i portfeli inwestycyjnych.
- System zarządzania treścią (CMS): CMS może wykorzystać Federację GraphQL do integracji danych z różnych źródeł, takich jak artykuły, obrazy, filmy i treści generowane przez użytkowników. Pozwala to na stworzenie zunifikowanego API do pobierania całej zawartości związanej z określonym tematem lub autorem.
- Aplikacja medyczna: Integracja danych pacjentów z różnych systemów, takich jak elektroniczna dokumentacja medyczna (EHR), wyniki laboratoryjne i harmonogram wizyt. Oferuje to lekarzom jeden punkt dostępu do kompleksowych informacji o pacjencie.
Dobre praktyki dla Schema Stitching
Aby zapewnić udaną implementację Schema Stitching, postępuj zgodnie z tymi najlepszymi praktykami:
- Starannie zaplanuj swój schemat: Zanim zaczniesz łączyć schematy, starannie zaplanuj strukturę zunifikowanego schematu. Obejmuje to zdefiniowanie relacji między typami z różnych schematów, zmianę nazw typów i pól w celu uniknięcia konfliktów oraz uwzględnienie ogólnych wzorców dostępu do danych.
- Używaj spójnych konwencji nazewnictwa: Przyjmij spójne konwencje nazewnictwa dla typów, pól i operacji we wszystkich usługach. Pomoże to uniknąć konfliktów i ułatwi zrozumienie zunifikowanego schematu.
- Dokumentuj swój schemat: Dokładnie dokumentuj zunifikowany schemat, włączając opisy typów, pól i operacji. Ułatwi to deweloperom zrozumienie i korzystanie ze schematu.
- Monitoruj wydajność: Monitoruj wydajność bramki i zdalnych usług, aby zidentyfikować i rozwiązać wszelkie wąskie gardła wydajnościowe. Używaj narzędzi, takich jak rozproszone śledzenie, do śledzenia żądań w wielu usługach.
- Wdróż zabezpieczenia: Zaimplementuj odpowiednie środki bezpieczeństwa, aby chronić bramkę i zdalne usługi przed nieautoryzowanym dostępem. Może to obejmować stosowanie mechanizmów uwierzytelniania i autoryzacji, a także walidację danych wejściowych i kodowanie danych wyjściowych.
- Wersjonuj swój schemat: W miarę ewolucji schematów, wersjonuj je odpowiednio, aby zapewnić, że klienci mogą nadal korzystać ze starszych wersji schematu bez awarii. Pomoże to uniknąć zmian powodujących niezgodność i zapewnić kompatybilność wsteczną.
- Automatyzuj wdrożenia: Zautomatyzuj wdrażanie bramki i zdalnych usług, aby zapewnić, że zmiany mogą być wdrażane szybko i niezawodnie. Pomoże to zmniejszyć ryzyko błędów i poprawić ogólną zwinność systemu.
Podsumowanie
Federacja GraphQL z Schema Stitching oferuje potężne podejście do budowania zunifikowanych interfejsów API z wielu usług w architekturze mikrousług. Rozumiejąc jej podstawowe koncepcje, korzyści, ograniczenia i techniki implementacji, możesz wykorzystać Schema Stitching do uproszczenia dostępu do danych, poprawy skalowalności i zwiększenia łatwości utrzymania. Chociaż Apollo Federation stała się bardziej zaawansowanym rozwiązaniem, Schema Stitching pozostaje realną opcją dla prostszych scenariuszy lub przy integracji istniejących usług GraphQL. Starannie rozważ swoje specyficzne potrzeby i wymagania, aby wybrać najlepsze podejście dla swojej organizacji.